package MONITORING::APPL::HP::NNM_OVSTATUS;

#################################################################
# $LastChangedDate: 2013-11-25 15:03:06 +0000 (Mon, 25 Nov 2013) $
# $LastChangedRevision: 22 $
# $LastChangedBy: aswod_83@gmx.net $
#################################################################
use strict;
use base qw(moniCA);
use XML::Simple;
use Data::Dumper;
use Params::Validate qw(:all);

#-------------------------------------------------------------------------------
sub Run {

#-------------------------------------------------------------------------------
# Description:
# Input Parms:
# Output Parms: None
#-------------------------------------------------------------------------------
    my $self      = shift;
    my $cnf       = $self->GetCNF();
    my $logger    = $self->GetLogger();
    my $statefile = $self->TmpDir() . '/' . $self->Plug() . '.xml';
    my %newstat;

    ##-------------------------------------
    #	validation of default parameters
    #-------------------------------------
    $self->_validCNFdefaults( $cnf->{defaults} );

    #-------------------------------------
    #	validation of identifier parameters
    #-------------------------------------
    $self->_validCNFidentifierAll();

    #-------------------------------------
    #	read cluster status from file or cmd
    #-------------------------------------

    my @ovstatus;
    if ( $self->{DefCfg}->{'Source'} eq 'File' ) {

        if ( -f $self->{DefCfg}->{'SourceFile'} ) {
            open( LOGFILE, "<$self->{DefCfg}->{'SourceFile'}" );
            @ovstatus = <LOGFILE>;
            close(IN);
            if ( ( stat( $self->{DefCfg}->{'SourceFile'} ) )[9] <=
                time() - $self->{DefCfg}->{'SourceFileMaxAge'} )
            {
                $logger->error("iEvent: NNMi ovstatus file too old");
                exit;
            }
        }
        else {
            $logger->error("iEvent: NNMi ovstatus file not found");
            exit;
        }
    }
    if ( $self->{DefCfg}->{'Source'} eq 'Cmd' ) {
        @ovstatus = qx($self->{DefCfg}->{'SourceCmd'});
    }
    if (@ovstatus) {
        chomp(@ovstatus);
        $logger->debug( Data::Dumper::Dumper(@ovstatus) );
    }
    else {
        $logger->error('iEvent: NNMi ovstatus empty');
        exit;
    }

    #-------------------------------------
    #	 put status into hash
    #-------------------------------------

    foreach my $line (@ovstatus) {
        next if ( $line =~ m/^\s*$/ );
        $line =~ s/^\s*//;
        $line =~ s/\s*$//;
        if ( $line =~ m/^object manager name:\s+(\S+)$/ ) {
            $self->{ID} = $1;
        }
        if ( $line =~ m/^state:\s+(\S+.*)$/ ) {
            $self->{identifier}->{ $self->{ID} }->{'status'} = $1;
        }
        if ( $line =~ m/^last message:\s+(\S+.*)$/ ) {
            $self->{identifier}->{ $self->{ID} }->{'last_mess'} = $1;
        }
        if ( $line =~ m/^exit status:\s+(\S+.*)$/ ) {
            $self->{identifier}->{ $self->{ID} }->{'exit_status'} = $1;
        }
    }

    #-------------------------------------
    #	 compare status with reference
    #-------------------------------------

    foreach ( keys %{ $self->{IdCfg} } ) {

        $self->{ID} = $_;
        Log::Log4perl::MDC->put( 'identifier', $self->{ID} );
        my %tmpstat;
        my $report = $self->{IdCfg}->{$_}->{'report'}
          || $self->{DefCfg}->{'report'};
        my $oldstat = XMLin( $statefile, ForceArray => 1 )->{identifier}->{$_}
          if ( -s $statefile );
        my $trigger = $self->{IdCfg}->{$_}->{'trigger'}
          || $self->{DefCfg}->{'trigger'};
        my $statusRef = $self->{IdCfg}->{$_}->{'statusRef'}
          || $self->{DefCfg}->{'statusRef'};

        $logger->error( "tEvent: No status for " . $_ . " available!" )
          unless $self->{identifier}->{$_}->{'status'};

        unless ( $statusRef eq $self->{identifier}->{$_}->{'status'} ) {
            $tmpstat{failCnt} = ( $oldstat->{failCnt} + 1 ) || 1;
            if ( $tmpstat{failCnt} == $trigger ) {
                $logger->error( "tEvent: "
                      . $_ . ": "
                      . $self->{identifier}->{$_}->{'status'} . " ["
                      . $statusRef
                      . "]" );
            }
            else {
                $logger->error( "iEvent: "
                      . $_ . ": "
                      . $self->{identifier}->{$_}->{'status'}
                      . " last_msg: "
                      . $self->{identifier}->{$_}->{'last_mess'} . " ["
                      . $statusRef
                      . "]" );
            }
            $logger->debug( $_
                  . " last message: "
                  . $self->{identifier}->{$_}->{'last_mess'} );
            $self->{identifier}->{$_}->{bool} = 0;
        }
        else {
            if ( $oldstat->{failCnt} >= $trigger ) {
                $logger->info( "cEvent: "
                      . $_ . ": "
                      . $self->{identifier}->{$_}->{'status'} );
            }
            else {
                $logger->info( "iEvent: "
                      . $_ . ": "
                      . $self->{identifier}->{$_}->{'status'} );
            }
            $tmpstat{failCnt} = 0;
            $self->{identifier}->{$_}->{bool} = 1;
        }
        $self->_validCNFrrd( $cnf->{rrd} ) && $self->_crReport()
          if ( $report =~ /on/i );
        $newstat{identifier}{$_} = \%tmpstat;
    }
    XMLout( \%newstat, outputfile => $statefile, NoSort => 0, XMLDecl => 1 );
}

#-------------------------------------------------------------------------------
sub _crReport {

#-------------------------------------------------------------------------------
# Description:
# Input Parms:
# Output Parms:
#-------------------------------------------------------------------------------

    my $self   = shift;
    my $logger = $self->GetLogger();

    eval {

        require RRDs;

        ( my $rrdident = $self->{ID} ) =~ s/\W/_/g;

        my $rrdfile =
            $self->{RRDCfg}->{rrdfilepath} . '/'
          . $self->Plug() . '_'
          . $rrdident . '.rrd'
          if ( -d $self->{RRDCfg}->{rrdfilepath} ) || die($!);
        my $rrdimg =
            $self->{RRDCfg}->{rrdimgpath} . '/'
          . $self->Plug() . '_'
          . $rrdident . '.png'
          if ( -d $self->{RRDCfg}->{rrdimgpath} ) || die($!);

        if ( !-f $rrdfile ) {

            my @rrdc;
            push( @rrdc, "$rrdfile" );
            push( @rrdc, "--step=$self->{RRDCfg}->{step}" );
            if ( ref( $self->{RRDCfg}->{DS} ) eq "ARRAY" ) {
                for ( @{ $self->{RRDCfg}->{DS} } ) { push( @rrdc, $_ ); }
            }
            else {
                push( @rrdc, $self->{RRDCfg}->{DS} );
            }
            for ( @{ $self->{RRDCfg}->{RRA} } ) { push( @rrdc, $_ ); }

            RRDs::create(@rrdc);

            $logger->warn( "RRDs::create returns " . RRDs::error() )
              if ( RRDs::error() );
        }

        my @identlist;
        if ( ref( $self->{RRDCfg}->{DS} ) eq "ARRAY" ) {
            for ( @{ $self->{RRDCfg}->{DS} } ) {
                my @tmplist = split( /:/, $_ );
                push( @identlist, $tmplist[1] );
            }
        }
        else {
            my @tmplist = split( /:/, $self->{RRDCfg}->{DS} );
            push( @identlist, $tmplist[1] );
        }
        my $dslist = join( ":", @identlist );

        if ( -f $rrdfile ) {
            my @rrdu;
            my @dsvalue;
            for (@identlist) {
                push( @dsvalue, $self->{identifier}->{ $self->{ID} }->{$_} );
            }
            my $dsvalue = join( ":", @dsvalue );

            push( @rrdu, "$rrdfile" );
            push( @rrdu, "--template=$dslist" );
            push( @rrdu, "N:$dsvalue" );

            RRDs::update(@rrdu);

            $logger->warn( "RRDs::update returns " . RRDs::error() )
              if ( RRDs::error() );

            my @rrdg;
            $rrdfile =~ s/\:\//\\\:\//g if ( $^O eq 'MSWin32' );

            push( @rrdg, "$rrdimg" );
            push( @rrdg, "--title=$self->{RRDCfg}->{'title'}: $self->{ID}" );
            push( @rrdg, "--start=$self->{RRDCfg}->{'start'}" );
            push( @rrdg, "--end=$self->{RRDCfg}->{'end'}" );
            push( @rrdg, "--vertical-label=$self->{RRDCfg}->{'label'}" );
            push( @rrdg, "--imgformat=$self->{RRDCfg}->{'imgformat'}" );
            push( @rrdg, "--watermark=$self->{RRDCfg}->{'watermark'}" );
            push( @rrdg, "--width=$self->{RRDCfg}->{'width'}" );
            push( @rrdg, "--height=$self->{RRDCfg}->{'height'}" );
            push( @rrdg, "--base=$self->{RRDCfg}->{'base'}" );
            push( @rrdg, "--upper-limit=$self->{RRDCfg}->{'upper-limit'}" );
            push( @rrdg, "--lower-limit=$self->{RRDCfg}->{'lower-limit'}" );

            foreach ( keys %{ $self->{RRDCfg}->{DEF} } ) {
                push( @rrdg,
                    "DEF:$_=$rrdfile:$_:$self->{RRDCfg}->{DEF}->{$_}->{CF}" );
                push( @rrdg,
"$self->{RRDCfg}->{DEF}->{$_}->{TYPE}:$_#$self->{RRDCfg}->{DEF}->{$_}->{COLOR}:$_ $self->{RRDCfg}->{DEF}->{$_}->{CF}"
                );
            }

            RRDs::graph(@rrdg);

            $logger->warn( "RRDs::graph returns " . RRDs::error() )
              if ( RRDs::error() );
        }
        1;
    } or $logger->debug( "Report incomplete: " . $@ );

}

#-------------------------------------------------------------------------------
sub _validCNFrrd {

#-------------------------------------------------------------------------------
# Description:
# Input Parms:
# Output Parms:
#-------------------------------------------------------------------------------
    my $self = shift;

    Params::Validate::validation_options( allow_extra => 1 );
    $self->{RRDCfg} = validate(
        @_,
        {
            'rrdfilepath' => {
                type     => SCALAR,
                default  => $self->VarDir(),
                optional => 1,
                regex    => qr/^.+$/
            },
            'rrdimgpath' => {
                type     => SCALAR,
                default  => $self->VarDir() . "/images",
                optional => 1,
                regex    => qr/^.+$/
            },
            'title' => { type => SCALAR },
            'label' => { type => SCALAR },
            'width' =>
              { type => SCALAR, default => "400", regex => qr/\d\d\d/ },
            'height' =>
              { type => SCALAR, default => "100", regex => qr/\d\d\d/ },
            'base'        => { type => SCALAR, default => 1000 },
            'upper-limit' => { type => SCALAR, default => 100 },
            'lower-limit' => { type => SCALAR, default => 0 },
            'start'       => { type => SCALAR, default => "end-24hours" },
            'end'         => { type => SCALAR, default => "now" },
            'imgformat'   => { type => SCALAR, regex   => qr/[PNG||GIF||PDF]/ },
            'watermark'   => {
                type    => SCALAR,
                default => "powered by Andre Schmitt"
            },
            'DS'  => { type => ARRAYREF | SCALAR },
            'RRA' => { type => ARRAYREF | SCALAR }
        }
    );
    return $self;

}

#-------------------------------------------------------------------------------
sub _validCNFdefaults {

#-------------------------------------------------------------------------------
# Description:
# Input Parms:
# Output Parms:
#-------------------------------------------------------------------------------
    my $self = shift;

    Params::Validate::validation_options( allow_extra => 1 );
    $self->{DefCfg} = validate(
        @_,
        {
            'Source'    => { type => SCALAR, regex => qr/^(File||Cmd)$/ },
            'report'    => { type => SCALAR, regex => qr/^(on||off)$/i },
            'trigger'   => { type => SCALAR, regex => qr/^.+$/ },
            'statusRef' => { type => SCALAR, regex => qr/^.+$/ }
        }
    );
    return $self;
}

#-------------------------------------------------------------------------------
sub _validCNFidentifier {

#-------------------------------------------------------------------------------
# Description:
# Input Parms:
# Output Parms:
#-------------------------------------------------------------------------------
    my $self = shift;
    my $cnf  = $self->GetCNF();

    Params::Validate::validation_options( allow_extra => 0 );
    $self->{IdCfg}->{ $self->{ID} } = validate(
        @_,
        {
            'report' =>
              { type => SCALAR, regex => qr/^(on||off)$/i, optional => 1 },
            'trigger'   => { type => SCALAR, regex => qr/^.+$/, optional => 1 },
            'statusRef' => { type => SCALAR, regex => qr/^.+$/, optional => 1 }
        }
    );
    return $self;
}

#-------------------------------------------------------------------------------
sub _validCNFidentifierAll {

#-------------------------------------------------------------------------------
# Description:
# Input Parms:
# Output Parms:
#-------------------------------------------------------------------------------
    my $self = shift;
    my $cnf  = $self->GetCNF();

    foreach ( keys %{ $cnf->{identifier} } ) {
        $self->{ID} = $_;
        $self->_validCNFidentifier( $cnf->{identifier}->{$_} );
    }
}
1;

__END__
 
=pod
 
=head1 NAME
 
SOCKET_PORT.pm - monitors service availability 
 
=head1 SYNOPSIS
 
=head1 DESCRIPTION
 
=head1 PREREQUISITES
 
The follwing CPAN modules needs to be installed:
 
C<Log::Log4perl>
C<XML::Simple>
C<IO::Socket::INET>
C<Time::HiRes>

=head1 CONFIGURATION FILE
 
  By default
 
=head2 EXAMPLES
 
=head3 example of configuation file

=begin text

#################################################
Modul		MONITORING::APPL::HP::NNM_OVSTATUS
Logger		moniCA
LogLevel	INFO
Subject		moniCA HPNetworkNodeManagerStatus / ${APPL_NAME} / ${APPL_LAYER} / ${HOSTNAME}
Description	This moniCA plug checks ...

#DOC: 
#DOC: 
#DOC:	

<defaults>
	Source		=	File
	SourceFile	=	D:/Daten/ovstatus.log
	SourceCmd	=	/usr/bin/sudo /opt/OV/bin/ovstatus
	SourceFileMaxAge	=	800
	report	=	off
	trigger	=	2
	statusRef	= RUNNING
</defaults>

#DOC: 
#DOC: 
#DOC:	

<identifier OVsPMD>
</identifier>

<identifier pmd>
</identifier>

<identifier nnmaction>
</identifier>

<identifier nmsdbmgr>
</identifier>

<identifier ovjboss>
</identifier>

<rrd>
         # rrdimgpath  =
         # rrdfilepath =
         step          = 300
         DS            = DS:bool:GAUGE:600:0:1
         RRA           = RRA:AVERAGE:0.5:1:800
         RRA           = RRA:AVERAGE:0.5:6:800
         RRA           = RRA:AVERAGE:0.5:24:800
         RRA           = RRA:AVERAGE:0.5:288:800
         title         = OVSTATUS
         label         = boolean
         width         = 400
         height        = 100
         base          = 1000
		 upper-limit   = 100 
		 lower-limit   = 0 
         start         = end-24hours
         end           = now
         watermark     = powered by SAM
         imgformat     = PNG
         <DEF "bool">
                 CF    = AVERAGE
                 TYPE  = LINE2
                 COLOR = FFC0CB
         </DEF>
</rrd>


=cut
